(*DONT_TOUCH = "TRUE"*)
module multi_iir_top #(
    parameter ref_width = 8,
    parameter datin_width = 8,
    parameter daout_width = 16,
    parameter mux_num = 10
)
(
    input clk,
    input rst_n,

    input signed [ref_width - 1 : 0] sin_ref,
    input signed [ref_width - 1 : 0] cos_ref,

    input unsigned [datin_width - 1 : 0] datin_bram_r_data, //0-1023 10bit
    output datin_bram_r_en,
    output [clogb2(mux_num) - 1 : 0] datin_bram_r_addr,

    output [daout_width - 1 : 0] daout_bram_w_sin_data,
    output daout_bram_w_sin_we,
    output daout_bram_w_sin_en,
    output [clogb2(mux_num) - 1 : 0] daout_bram_w_sin_addr,

    output [daout_width - 1 : 0] daout_bram_w_cos_data,
    output daout_bram_w_cos_we,
    output daout_bram_w_cos_en,
    output [clogb2(mux_num) - 1 : 0] daout_bram_w_cos_addr,
    
    input start,
    input start_ref_lock,
    output update_flag
);
    
    reg [ref_width - 1 : 0] sin_ref_reg;
    reg [ref_width - 1 : 0] cos_ref_reg;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            sin_ref_reg <= {ref_width{1'b0}};
            cos_ref_reg <= {ref_width{1'b0}};
        end
        else begin
            if (start_ref_lock) begin
                sin_ref_reg <= sin_ref;
                cos_ref_reg <= cos_ref;
            end
        end
    end

    wire signed [datin_width + ref_width - 1 : 0] datin_sin_modulated;
    wire signed [datin_width + ref_width - 1 : 0] datin_cos_modulated;

    mult_unsign8_sign8 u_mult_unsign8_sign8_sin (
        .A(datin_bram_r_data),  // input wire [7 : 0] A
        .B(sin_ref_reg),  // input wire [7 : 0] B
        .P(datin_sin_modulated)  // output wire [15 : 0] P
    );
    mult_unsign8_sign8 u_mult_unsign8_sign8_cos (
        .A(datin_bram_r_data),  // input wire [7 : 0] A
        .B(cos_ref_reg),  // input wire [7 : 0] B
        .P(datin_cos_modulated)  // output wire [15 : 0] P
    );


    IIR_top #(
        .datin_width(datin_width + ref_width),
        .daout_width(daout_width),
        .mux_num(mux_num)
    ) u_IIR_top_sin (
        .clk(clk),
        .rst_n(rst_n),
        .start(start),
        .datin_bram_r_data(datin_sin_modulated),
        .datin_bram_r_en(datin_bram_r_en),
        .datin_bram_r_addr(datin_bram_r_addr),
        .daout_bram_w_data(daout_bram_w_sin_data),
        .daout_bram_w_we(daout_bram_w_sin_we),
        .daout_bram_w_en(daout_bram_w_sin_en),
        .daout_bram_w_addr(daout_bram_w_sin_addr),
        .update_flag(update_flag)
    );

    IIR_top #(
        .datin_width(datin_width + ref_width),
        .daout_width(daout_width),
        .mux_num(mux_num)
    ) u_IIR_top_cos (
        .clk(clk),
        .rst_n(rst_n),
        .start(start),
        .datin_bram_r_data(datin_cos_modulated),
        .datin_bram_r_en(),
        .datin_bram_r_addr(),
        .daout_bram_w_data(daout_bram_w_cos_data),
        .daout_bram_w_we(daout_bram_w_cos_we),
        .daout_bram_w_en(daout_bram_w_cos_en),
        .daout_bram_w_addr(daout_bram_w_cos_addr),
        .update_flag()
    );

function integer clogb2(input integer depth);
  integer tmp;
  begin
    tmp = depth;
    for (clogb2 = 0; tmp > 0; clogb2 = clogb2 + 1) 
      tmp = tmp >> 1;                          
  end
endfunction

endmodule